package com.yx.louti.advice;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.yx.louti.globalException.enums.HttpResultCode;
import com.yx.louti.globalException.model.BizException;
import com.yx.louti.globalException.model.HttpErrorResult;
import jtool.JReflect;
import jtool.JThrow;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 全局异常处理类
 *
 * @author sw-code
 * @RestControllerAdvice(@ControllerAdvice)，拦截异常并统一处理
 */
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionAdvice {
    private static final Log log = LogFactory.get();

    /**
     * 处理自定义的业务异常
     *
     * @param e       异常对象
     * @param request request
     * @return 错误结果
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BizException.class)
    public HttpErrorResult bizExceptionHandler(BizException e, HttpServletRequest request) {
        log.debug("{}", JThrow.toString(e));
        return HttpErrorResult.fail(e.getCode(), e.getMessage());
    }

    /**
     * 处理异常
     *
     * @param e       异常对象
     * @param request request
     * @return 错误结果
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(RuntimeException.class)
    public HttpErrorResult runtimeExceptionHandler(RuntimeException e, HttpServletRequest request) {
        log.error("运行异常", e);
        return HttpErrorResult.fail(-1, e.getMessage());
    }

    // 拦截抛出的异常，@ResponseStatus：用来改变响应状态码
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(Throwable.class)
    public HttpErrorResult handlerThrowable(Throwable e, HttpServletRequest request) {
        log.error(e.getMessage(), e);
        HttpErrorResult error = HttpErrorResult.fail(HttpResultCode.SYSTEM_ERROR.code(), e.getMessage());
        return error;
    }

    // 参数校验异常
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BindException.class)
    public HttpErrorResult handleBindExcpetion(BindException e, HttpServletRequest request) {
//        log.error("发生参数校验异常！原因是：", e);
        List<ObjectError> allErrors = e.getAllErrors();
        StringBuilder sb = new StringBuilder();
        sb.append("校验错误");
        for (ObjectError error : allErrors) {
            String field = JReflect.reflect(error).field("field").get();
            sb.append("\n").append(field + ":" + error.getDefaultMessage());
        }
        HttpErrorResult error = HttpErrorResult.fail(HttpResultCode.PARAM_IS_INVALID, e, sb.toString());
        return error;
    }

    // 参数校验异常
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public HttpErrorResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
//        log.error("发生参数校验异常！原因是：", e);
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        StringBuilder sb = new StringBuilder();
        sb.append("校验错误");
        for (ObjectError error : allErrors) {
            String field = JReflect.reflect(error).field("field").get();
            sb.append("\n").append(field + ":" + error.getDefaultMessage());
        }
        HttpErrorResult error = HttpErrorResult.fail(HttpResultCode.PARAM_IS_INVALID, e, sb.toString());
        return error;
    }
}
